package yxy.banana.socket.controller.server;

import yxy.apple.protobuf.Constants;
import yxy.apple.protobuf.Message.Parcal;
import yxy.apple.protobuf.internal.router.Message.RegistryRequest;
import yxy.apple.protobuf.internal.router.Message.RegistryResponse;
import yxy.apple.util.scheduler.Schedulable;
import yxy.apple.util.scheduler.ScheduledFuture;
import yxy.banana.socket.NetworkElement;
import yxy.banana.socket.controlled.ControlledHandler;

public abstract class ServerRegistryController<H extends ControlledHandler> extends ServerHeartbeatController<H> {

	private int timeout = 10000;

	private ScheduledFuture watching = null;

	private boolean registered = false;

	private class RegistryListener implements Schedulable {

		@Override
		public void trigger() {
			ServerRegistryController.this.watching = null;
			ServerRegistryController.this.unregistered();
		}

		@Override
		public void cancelled() {
		}
	}

	public ServerRegistryController(int heartbeatTimeout, int registryTimeout) {
		super(heartbeatTimeout);
		this.timeout = registryTimeout;
	}

	public boolean registered() {
		return this.registered;
	}

	@Override
	public void open() {
		super.open();
		this.watching = ServerRegistryController.scheduler.schedule(new RegistryListener(), this.timeout);
	}

	@Override
	public void close() {
		if (this.watching != null) {
			this.watching.cancel();
			this.watching = null;
		}
		super.close();
	}

	@Override
	public boolean control(Parcal parcal) throws Exception {
		if (super.control(parcal)) {
			return true;
		} else if (parcal.getProto() == Constants.ControlProto.RegistryRequest) {
			boolean result = false;
			try {
				RegistryRequest request = RegistryRequest.parseFrom(parcal.getData());
				int system = request.getSystem();
				int cluster = request.getCluster();
				// 不允许重复注册
				if (!this.registered && this.register(system, cluster)) {
					this.registered = true;
					result = true;
					if (this.watching != null) {
						this.watching.cancel();
						this.watching = null;
					}
					this.registered(system, cluster);
				}
				try {
					RegistryResponse.Builder builder = RegistryResponse.newBuilder();
					builder.setResult(result);
					RegistryResponse response = builder.build();
					long s = NetworkElement.value(this.handler().system(), this.handler().cluster(), this.handler().channel());
					long d = parcal.getSource();
					this.handler().send(parcal.getTag(), s, d, Constants.ControlProto.RegistryResponse, response);
				} catch (Exception e) {
					this.caught(e);
				}
			} catch (Exception e) {
				this.caught(e);
			}
			if (!result) {
				this.unregistered();
			}
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 处理成功时回调，多数情况下，业务逻辑从此作为起点开始工作
	 * 
	 * @param from
	 * @param to
	 * @param exclusion
	 */
	protected abstract void registered(int system, int cluster);

	/**
	 * 未能成功完成注册时回调
	 */
	protected abstract void unregistered();

	/**
	 * 处理注册
	 * 
	 * @param from
	 * @param to
	 * @param exclusion
	 * @return
	 */
	protected abstract boolean register(int system, int cluster);

}
